package com.liuwei.msmall.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.liuwei.msmall.common.utils.PageUtils;
import com.liuwei.msmall.common.utils.Query;
import com.liuwei.msmall.product.dao.CategoryDao;
import com.liuwei.msmall.product.entity.CategoryBrandRelationEntity;
import com.liuwei.msmall.product.entity.CategoryEntity;
import com.liuwei.msmall.product.service.CategoryBrandRelationService;
import com.liuwei.msmall.product.service.CategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;


@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {

    @Resource
    CategoryBrandRelationService categoryBrandRelationService;

    @Autowired
    StringRedisTemplate redisTemplate;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<CategoryEntity> page = this.page(
                new Query<CategoryEntity>().getPage(params),
                new QueryWrapper<CategoryEntity>()
        );

        return new PageUtils(page);
    }


    @Override
    public List<CategoryEntity> listTree() {
        //拿到所有分类
        List<CategoryEntity> allCategorys = this.list();
        System.out.println("查询了数据库。。。。。");
        if (!CollectionUtils.isEmpty(allCategorys)){

            List<CategoryEntity> collect = allCategorys.stream().filter(c -> c.getParentCid().longValue() == 0).map(i -> {
                i.setChildrens(getCatChildren(i.getCatId(),allCategorys));
                return i;
            }).sorted(Comparator.comparingInt(cat -> (cat.getSort() == null ? 0 : cat.getSort())))
                    .collect(Collectors.toList());

            return collect;
        }

        return Lists.newArrayList();
    }


    @CacheEvict(value = {"category"},key = "'getCatelogLevel1'") //删除分类的时候也删除缓存
    @Transactional
    @Override
    public void removeBatchByIds(List<Long> asList) {
        //删除分类品牌关联表
        categoryBrandRelationService.remove(new QueryWrapper<CategoryBrandRelationEntity>().in("catelog_id",asList));

        //TODO 判断有没有其他商品引用
        //删除自己
        this.removeByIds(asList);

        //判断自己的子分类
        List<CategoryEntity> childrens = this.list(new LambdaQueryWrapper<CategoryEntity>().eq(CategoryEntity::getParentCid, asList.get(0)));
        if (!CollectionUtils.isEmpty(childrens)){
            this.removeByIds(childrens.stream().map(cat->cat.getCatId()).collect(Collectors.toList()));
        }

    }

    @Caching(evict = {
            @CacheEvict(value = {"category"},key = "'getCatelogLevel1'")
    })//更新分类时删除缓存
    @Transactional
    @Override
    public void updateCascade(CategoryEntity category) {
        //更新自己
        this.updateById(category);
        //更新分类关联表
        CategoryBrandRelationEntity relationEntity = new CategoryBrandRelationEntity();
        relationEntity.setCatelogId(category.getCatId());
        relationEntity.setCatelogName(category.getName());
        categoryBrandRelationService.update(relationEntity,new UpdateWrapper<CategoryBrandRelationEntity>().eq("catelog_id",category.getCatId()));

    }

    @Override
    public Map<Long, String> getCateMap(List<Long> catIds) {
        Map<Long,String > cateMaps =  new HashMap<>();
        if (CollectionUtils.isEmpty(catIds)){
            return cateMaps;
        }
        List<CategoryEntity> entities = this.list(new LambdaQueryWrapper<CategoryEntity>().in(CategoryEntity::getCatId, catIds));
        if (CollectionUtils.isEmpty(entities)){
            return cateMaps;
        }
        return entities.stream().collect(Collectors.toMap(CategoryEntity::getCatId, CategoryEntity::getName));
    }

    @Override
    public Long[] getCatePathById(Long catelogId) {
        List<Long> pathIds = Lists.newArrayList();

        findParentId(catelogId,pathIds);

        Collections.reverse(pathIds);

        return pathIds.toArray(new Long[pathIds.size()]);
    }

    @Cacheable(cacheNames = {"category"},key = "#root.method.name")
    @Override
    public List<CategoryEntity> getCatelogLevel1() {

        //todo 加缓存，对于分类数据不经常改变，但经常访问的数据
        //1,设置null值缓存，解决缓存穿透
        //2,设置key过期时间为随机值，解决缓存雪崩
        //3，加锁，解决缓存击穿问题

        //从缓存中取，
//        String category = redisTemplate.opsForValue().get("category");
//
//        if (StringUtils.isEmpty(category)){
//
//            synchronized (this){
//
//                String category2 = redisTemplate.opsForValue().get("category");
//                if (StringUtils.isEmpty(category2)){
//                    //从数据库查询
//                    List<CategoryEntity> list = listTree();
//                    redisTemplate.opsForValue().set("category",JSON.toJSONString(list));
//                    return list;
//                }
//                return JSON.parseObject(category2,new TypeReference<List<CategoryEntity>>(){});
//            }
//
//        }
//
//        return JSON.parseObject(category,new TypeReference<List<CategoryEntity>>(){});
        return listTree();
    }

    private void findParentId(Long catelogId, List<Long> pathIds) {
        pathIds.add(catelogId);

        CategoryEntity categoryEntity = this.getById(catelogId);
        if (categoryEntity.getParentCid()!=0){
            findParentId(categoryEntity.getParentCid(),pathIds);
        }
        return;
    }

    private List<CategoryEntity> getCatChildren(Long catId,List<CategoryEntity> all) {

            List<CategoryEntity> collect = all.stream().filter(c -> c.getParentCid().longValue() ==  catId.longValue()).map(i -> {
                i.setChildrens(getCatChildren(i.getCatId(),all));
                return i;
            }).sorted(Comparator.comparingInt(cat -> (cat.getSort() == null ? 0 : cat.getSort())))
                    .collect(Collectors.toList());
            return collect;
    }

}
